iT邦幫忙

2022 iThome 鐵人賽

DAY 7
0

Medium 清新閱讀版連結

今天是鐵人賽第7天了!

前面幾天我們介紹了測試3A原則,也介紹了許多 Assertion 函數,今天就讓我們實際演練吧!

過去的經驗中,最常用自動化測試來測式的對象,大概就是API了,而前後端分離也是目前 Web 開發界常用的模式,因此我們就以 API 測試來演練吧!

驗證HTTP Status Code

HTTP Status Code 的驗證,應該是最常遇到的 API 測試情境了,其實前面的 Assertion 函數範例中也有展示部分使用方式了,這次讓我們更完整地演練吧!

提醒一點,由於以下的測試會牽涉到資料庫,因此大家要再檢查一下 phpunit.xml 中的資料庫連線設定是否已填上,詳情可參考前Day 6文章內容。

另值得一提的是,為了方便取用路由路徑,在設置路由時,通常都會將路由命名。

案例1:200—索取使用者資料

  • routes/api.php
<?php

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/users', function (Request $request) {
    $users = User::all();

    return response()->json([
        'users' => $users,
    ]);
})->name('get.user.list');
  • tests/Feature/HttpStatusCodeTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class HttpStatusCodeTest extends TestCase
{
    use RefreshDatabase;

    public function testCanGetUserListWhenEmpty()
    {
        $response = $this->get(route('get.user.list'));
        $response->assertOk();

        // 也可以寫成以下串聯寫法
        $this->get(route('get.user.list'))
            ->assertOk();
    }
}

在以上程式碼中, users 資料表尚無任何User資料,但取得User清單的端點也應該要能正常回應,透過以上測試程式碼,可以驗證此行為是否正常運作。

案例2:404—索取不存在之使用者資料

  • routes/api.php

    <?php
    
    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/users/{id}', function (Request $request, $id) {
        $user = User::find($id);
    
        if (empty($user)) {
            return response()->json([
                'error' => 'Not Found',
            ], 404);
        }
    
        return response()->json([
            'user' => $user,
        ]);
    })->where('id', '[0-9]?')->name('get.user');
    
  • tests/Feature/HttpStatusCodeTest.php

    <?php
    
    namespace Tests\Feature;
    
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class HttpStatusCodeTest extends TestCase
    {
        use RefreshDatabase;
    
        public function testCanGetNotFoundWhenNoGivenUser()
        {
            $response = $this->get(route('get.user', ['id' => 1,]));
            $response->assertNotFound();
    
            // 也可以寫成以下串聯寫法
            $this->get(route('get.user', ['id' => 1,]))
                ->assertNotFound();
        }
    }
    

    在以上程式碼中, users 資料表尚無任何User資料,因此當嘗試取得 id=1 之 User 資源時,應會找不到,也就是404,透過以上測試程式碼,可以驗證此行為是否正常運作。

案例3:422—請求驗證未通過

  • routes/api.php

    <?php
    
    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    
    Route::post('/users', function (Request $request) {
    
        $request->validate([
            'name' => 'required|string',
            'email' => 'required|email',
            'password' => 'required|string',
        ]);
    
        $user = User::create($request->all());
    
        return response()->json([
            'user' => $user,
        ]);
    })->name('store.user');
    
  • tests/Feature/HttpStatusCodeTest.php

    <?php
    
    namespace Tests\Feature;
    
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class HttpStatusCodeTest extends TestCase
    {
        use RefreshDatabase;
    
        public function testCanResponseUnprocessableWhenInvalidRequest()
        {
            $response = $this->post(
                route('store.user'),
                ['name' => ''],
                ['Accept' => 'application/json']
            );
            $response->assertUnprocessable();
    
            // 也可以寫成以下串聯寫法
            $this->post(
                    route('store.user'),
                    ['name' => ''],
                    ['Accept' => 'application/json']
                )
                ->assertUnprocessable();
        }
    }
    

    在以上程式碼中, 我們建立了一個可以建立 User 資料的路由端點,與實作建立資料流程,並在這當中建立了驗證請求資料的邏輯,而在下方的測試案例中,我們測試了「當請求內容有缺失時,應回應 422 Unprocessable Entity」這個行為是否正常運作。

驗證Response JSON

除了前面介紹的 HTTP Status Code 驗證,在測試 API 時,另一個常常需要做驗證的部分,應該就是回應JSON的內容本身了,以下就讓我們來看看實例吧!

案例1:驗證回應JSON內容

  • routes/api.php

    <?php
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/users', function (Request $request) {
        // 這邊先用假的 User 資料
        $users = [
            [
                'id' => 1,
                'name' => 'name1',
                'email' => 'user1@email.com',
            ],
            [
                'id' => 1,
                'name' => 'name1',
                'email' => 'user1@email.com',
            ],
        ];
    
        return response()->json([
            'users' => $users,
        ]);
    })->name('get.user.list');
    
  • tests/Feature/HttpStatusCodeTest.php

    <?php
    
    namespace Tests\Feature;
    
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class HttpStatusCodeTest extends TestCase
    {
        use RefreshDatabase;
    
        public function testCanGetUserJson()
        {
            $response = $this->get(route('get.user.list'));
            $response->assertJson([
                'users' => [
                    [
                        'id' => 1,
                        'name' => 'name1',
                        'email' => 'user1@email.com',
                    ],
                    [
                        'id' => 1,
                        'name' => 'name1',
                        'email' => 'user1@email.com',
                    ],
                ]
            ]);
    
            // 也可以寫成以下串聯寫法
            $this->get(route('get.user.list'))
                ->assertJson([
                    'users' => [
                        [
                            'id' => 1,
                            'name' => 'name1',
                            'email' => 'user1@email.com',
                        ],
                        [
                            'id' => 1,
                            'name' => 'name1',
                            'email' => 'user1@email.com',
                        ],
                    ]
                ]);
        }
    }
    

    在以上程式碼中, 我們建立了一個可以取得 User 清單的端點,並且驗證在呼叫此 API 後,其回應的JSON是否符合預期。

案例2:驗證回應JSON結構

  • routes/api.php

       <?php
    
        use Illuminate\Http\Request;
        use Illuminate\Support\Facades\Route;
    
        Route::get('/users', function (Request $request) {
            // 這邊先用假的 User 資料
            $users = [
                [
                    'id' => 1,
                    'name' => 'name1',
                    'email' => 'user1@email.com',
                ],
                [
                    'id' => 1,
                    'name' => 'name1',
                    'email' => 'user1@email.com',
                ],
            ];
    
            return response()->json([
                'users' => $users,
            ]);
        })->name('get.user.list');
    
  • tests/Feature/HttpStatusCodeTest.php

    <?php
    
    namespace Tests\Feature;
    
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class HttpStatusCodeTest extends TestCase
    {
        use RefreshDatabase;
    
        public function testCanGetUserJsonStructure()
        {
            $response = $this->get(route('get.user.list'));
    
            // '*' 代表是每陣列元素
            // 此寫法相當於驗證 'users' 是一個陣列
            // 每個陣列元素是一個物件
            // 每個物件有 id, name, email 這幾個欄位
            $response->assertJsonStructure([
                'users' => [
                    '*' => [
                        'id',
                        'name',
                        'email'
                    ],
                ],
            ]);
    
            // 也可以寫成以下串聯寫法
            $this->get(route('get.user.list'))
                ->assertJsonStructure([
                    'users' => [
                        '*' => [
                            'id',
                            'name',
                            'email'
                        ],
                    ],
                ]);
        }
    }
    

    另一種常見的情況,是只驗證 JSON 結構,而略過驗證 JSON 的鍵與值。

以上就是今天的介紹,大家可以多加練習看看!

明天讓我們來練習資料庫測試吧!


上一篇
常用 Assertion 函數(三)
下一篇
資料庫測試
系列文
自動化測試大作戰31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言